package service

import (
	"context"
	"errors"
	"fmt"
	"seckill/utils"
	"strconv"
	"time"
)

// QueryRedisV1 用户id
func QueryRedisV1(goodId, userId int) {
	defer utils.Wg.Done()
	// 获取redis的连接池
	redisClient := utils.GlobalRedisDb
	var ctx = context.Background()
	isFlag, err := redisClient.SetNX(ctx, "limit:userId:"+strconv.Itoa(userId), userId, time.Second*3).Result()
	if err != nil {
		fmt.Println("设置redis缓存失败")
		return
	}
	if !isFlag {
		fmt.Println("操作过于频繁，请稍后在试！")
		return
	}
	// 判断订单缓存中是否已经存在这个用户id，避免重复下单
	result, err2 := redisClient.HGetAll(ctx, "save:userId").Result()
	if err2 != nil {
		fmt.Println("获取全部的用户失败")
		return
	}
	_, isOk := result[strconv.Itoa(userId)]
	if isOk {
		fmt.Println("订单已经存在,请不要重复下单")
		return
	}
	// 从redis中扣减库存
	redisCount, err3 := redisClient.DecrBy(ctx, "id:"+strconv.Itoa(goodId), 1).Result()
	if err3 != nil {
		fmt.Println("扣减库存失败" + err3.Error())
		return
	}
	if redisCount > 0 {
		//其实这里就可以记录下来抢购到的用户Id，然后做后续的业务处理，其实也就是统计有哪些用户已经下单成功了。
		//将下单的用户id保存起来。
		//其实这里的业务，如果你是百万级用户，也可以将用户Id写入到RabbitMq里面。
		_, err := redisClient.HSet(ctx, "save:userId", strconv.Itoa(userId), userId).Result()
		if err != nil {
			//这里如果说redis宕机了`或者其他异常的话，这里就应该用IncrBy增加一条库存数量，因为他是在decr减掉库存后才宕机的，所有要补偿1条库存。
			fmt.Println("设置redis库存失败" + err.Error())
			return
		}
		fmt.Println("用户下单成功", userId)
	} else {
		fmt.Printf("库存不足,用户Id：%d 下单失败！\n", userId)
		//补偿redis中的数据为0，如果不补偿redis中的数据会为负数
		_, err := redisClient.Set(ctx, "id:"+strconv.Itoa(goodId), 0, 0).Result()
		if err != nil {
			fmt.Println("补偿redis库存失败")
			return
		}
	}
}

// QueryRedisV2 用户id
func QueryRedisV2(goodId, userId int) (string, error) {
	// 获取redis的连接池
	redisClient := utils.GlobalRedisDb
	var ctx = context.Background()
	isFlag, err := redisClient.SetNX(ctx, "limit:userId:"+strconv.Itoa(userId), userId, time.Second*3).Result()
	if err != nil {
		return "", errors.New("设置redis缓存失败")
	}
	if !isFlag {
		return "", errors.New("操作过于频繁，请稍后在试！")
	}
	// 判断订单缓存中是否已经存在这个用户id，避免重复下单
	result, err2 := redisClient.HGetAll(ctx, "save:userId").Result()
	if err2 != nil {
		//fmt.Println("获取全部的用户失败")
		return "", errors.New("获取全部的用户失败")
	}
	_, isOk := result[strconv.Itoa(userId)]
	if isOk {
		//fmt.Println("订单已经存在,请不要重复下单")
		return "", errors.New("订单已经存在,请不要重复下")
	}
	// 从redis中扣减库存
	redisCount, err3 := redisClient.DecrBy(ctx, "id:"+strconv.Itoa(goodId), 1).Result()
	if err3 != nil {
		//fmt.Println("扣减库存失败" + err3.Error())
		return "", errors.New("扣减库存失败" + err3.Error())
	}
	fmt.Println(redisCount, "当前库存数量")
	if redisCount >= 0 {
		//其实这里就可以记录下来抢购到的用户Id，然后做后续的业务处理，其实也就是统计有哪些用户已经下单成功了。
		//将下单的用户id保存起来。
		//其实这里的业务，如果你是百万级用户，也可以将用户Id写入到RabbitMq里面。
		_, err := redisClient.HSet(ctx, "save:userId", strconv.Itoa(userId), userId).Result()
		if err != nil {
			//这里如果说redis宕机了`或者其他异常的话，这里就应该用IncrBy增加一条库存数量，因为他是在decr减掉库存后才宕机的，所有要补偿1条库存。
			//fmt.Println("设置redis库存失败" + err.Error())
			return "", errors.New("设置redis库存失败" + err.Error())
		}
		//fmt.Println("用户下单成功", userId)
		return fmt.Sprintf("用户下单成功:%d", userId), nil
	} else {
		//fmt.Printf("库存不足,用户Id：%d 下单失败！\n", userId)
		//补偿redis中的数据为0，如果不补偿redis中的数据会为负数
		_, err := redisClient.Set(ctx, "id:"+strconv.Itoa(goodId), 0, 0).Result()
		if err != nil {
			//fmt.Println("补偿redis库存失败")
			return "", errors.New("补偿redis库存失败" + err.Error())
		}
		return "", errors.New(fmt.Sprintf("库存不足,用户Id：%d 下单失败！\n", userId))
	}
}

// SetStore 设置库存
func SetStore(goodId, count int) {
	redisClient := utils.GlobalRedisDb
	var ctx = context.Background()
	// 先清空库存
	_, err1 := redisClient.Del(ctx, "id:"+strconv.Itoa(goodId)).Result()
	if err1 != nil {
		fmt.Println("清空商品库存失败")
		return
	}
	_, err2 := redisClient.IncrBy(ctx, "id:"+strconv.Itoa(goodId), int64(count)).Result()
	if err2 != nil {
		fmt.Println("设置库存失败")
		return
	}
}
